为方便理解Conductor的机制,我们不妨结合业务场景来讲,如果我们要访问应用A进行用户信息查询,传统的处理方式如下:
传统的处理方式耦合度非常高,当需要调整某个模块时会涉及到其他模块的接口的交互和稳定性,从MVC到SOA,以及到现在的微服务,都在一定程度上解决模块与模块之间的耦合度问题。
我们接着拆分,如果接入SSO,增加认证方式,处理的方式就会变成如下形式:
这里把认证模块独立为一个应用对外提供服务,这就是我们耳熟能详的SSO雏形。
接着对某些数据进行加密处理后再进行展现,我们如果不改造应用A又该怎么处理呢?当然增加API网关是可以达到相同的目的,处理方式变成如下:
API网关增加加密插件模块,配置应用A对外提供服务,对访问应用API的特定URL数据进行加密处理或解析相应的数据变量进行定位处理,虽然复杂些,但也能达到想要的效果,只不过一旦应用A需要加密的变量发生变化,API网关同样存在重新调整的风险,耦合度还是太高。
现在我们再进一步场景细化,看看该如何处理。
如果要把应用A加密的数据给应用B来展现呢?或者B获取到A的加密数据后进行处理,把处理后的数据再返回给应用A展现呢?(典型的有OCSP、证书的签名与验签案例)。
当然如果非要用API网关解决也是可以的,但随着业务的复杂度,API网关的业务逻辑耦合度会越来越高,崩溃只是时间问题。何况API网关是用来解决访问安全问题的,并不适合处理复杂的业务逻辑问题。
那么该怎么解决类似的问题呢?
Conductor的架构为我们提供了优雅解决这些问题的方法,它的处理模式如下:
从上图我们可以看出Conductor是如何编排各个微服务的,由于整个机制为事件驱动模式,需要应用集成Conductor的客户端SDK,任务分为System Task(在Conductor服务器的JVM内执行,由Conductor管理)和Worker Task(由应用实现并在独立的环境中运行)。
最后我们来看看Conductor的运行模式(如下图—来自官网)
Worker作为应用端,可以用任何语言实现,这些任务通过REST API或gRPC机制与Conductor服务端通讯,以轮询任务的方式执行后再更新其状态。Task Queues用于为Worker编排的任务,可以与SQS(Simple Queue Service)或发布与订阅(Pub/Sub)机制进行交换,Conductor持久化模块使用Dynomite(分布式的缓存系统)存储状态,以及用Elasticsearch(分布式多用户能力的全文搜索引擎)用于索引后端,当然这些根据实际的业务需求都是可替换的。